<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2018/3/15 0015
 * Time: 下午 4:29
 */

namespace App\Models;


use function GuzzleHttp\Psr7\str;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Redis;

class CurrencyLog extends  Model
{
    protected $table = 'currency_log';

    protected $fillable = [
        'id',
        'cid', //币种ID
        'open_price', //开盘价
        'close_price', //收盘价
        'time',//当日凌晨的时间戳
        'lower_price',//当日凌晨的时间戳
        'high_price',//当日凌晨的时间戳
        'minute_ident',//当日凌晨的时间戳,
        'amount' //数量
    ];

    public function unit($name){
        switch ($name){
            case 'TRX':
            case 'DOGE':
                return 4;
            default:
                return 2;
        }
    }
    /**
     * 获取昨天的收盘价
     * @date 2018/03/16
     * @author yanggang
     * @param $id 货币id
     * @return int 收盘价
     */
    public function get_last_close_price($id)
    {
        $yesterday_time = strtotime(date('Y-m-d',strtotime('-1day')));
        $currency_log = $this->where(['cid'=>$id,'time'=>$yesterday_time])->orderBy('minute_ident','desc')->first();
        if (!$currency_log){
            return Currency::where(['id'=>$id])->value('official_price');
        }
        return $currency_log['close_price'];

    }

    /**
     * 获取DIF
     * @author yanggang
     * @date 2018/03/17
     * @param $EMA12
     * @param $EMA26
     * @return array
     */
    protected function get_DIF($EMA12,$EMA26)
    {
        $DIF = [];
        foreach ($EMA12 as $key=>$item) {
            array_push($DIF,floatval($item)-floatval($EMA26[$key]));
        }
        return $DIF;
    }

    /**
     * 获取MACD
     * @author yanggang
     * @date 2018/03/17
     * @param $dif_arr
     * @param $dea_arr
     * @return array
     */
    protected function get_MACD($dif_arr, $dea_arr)
    {
        $macd_arr = [];
        foreach ($dif_arr as $key=>$item){
            array_push($macd_arr,($item - $dea_arr[$key]) * 2);
        }
        return $macd_arr;
    }

    /**
     * 均线图
     * @param $id 币种id
     * @param $date_type 均线图的时间 0 查前5天 1 查前10天
     * @return int|string
     */
    public function get_MA5($id,$date_type=0)
    {
        $ma_date = [5,10];
        $date = $ma_date[$date_type];
        $res = $this->where(['cid'=>$id,'ident_minute'=>1440])->orderBy('id','desc')->limit($date)->get();
        if (!$res){
            return 0;
        }
        $sum = 0;
        foreach ($res as $item){
            $sum += $item['close_price'];
        }

        return  number_format($sum/$date,2);
    }

    /**
     * 量柱图
     * @param $id 币种id
     * @return array
     */
    public function get_order_amount($id)
    {

        $res = $this->where(['cid'=>$id])->orderBy('id','desc')->get();
        $amount = [];
        if (!$res){
            return [];
        }
        foreach ($res as $item){
            array_push($amount,$item['amount']);
        }

        return $amount;
    }

    /**
     * 量均线
     * @param $id 币种id
     * @param $date_type 均线图的时间 0 查前5天 1 查前10天
     * @return int|string
     */
    public function get_amount_avg($id,$date_type=0)
    {
        $ma_date = [5,10];
        $date = $ma_date[$date_type];
        $res = $this->where(['cid'=>$id])->orderBy('id','desc')->limit($date)->get();
        if (!$res){
            return 0;
        }
        $sum = 0;
        foreach ($res as $item){
            $sum += $item['amount'];
        }

        return  number_format($sum/$date,2);
    }

    /**
     * @param $id 币种id
     * @param $time_type 时间区间
     * 时间区间 默认为1天  1 1分钟，2 5分钟， 3 15分钟， 4 30分钟， 5 1小时， 6 4小时，7 5天， 8 7天， 9 30天
     * 1分钟   查前5个小时的数据
     * 5分钟   查前25个小时的数据
     * 15分钟  查前75个小时的数据
     * 30分钟  查前150个小时的数据
     * 1小时   查前297个小时的数据
     * 4小时   查前1200个小时的数据
     * 1天     查前144天的数据
     * 1天以上 查全部的数据
     * @return array
     */
    protected function get_kline($id,$time_type=0)
    {
        // 开始和结束时间相差的时间（分钟），用来计算开始时间和结束时间
        $date_type = [
            0=>144*24*60,
            1=>5*60,
            2=>25*60,
            3=>75*60,
            4=>150*60,
            5=>297*60,
            6=>1200*60,
            7=>5*24*60,
            8=>7*24*60,
            9=>30*24*60,
        ];
        // 相隔记录条数，用来查询汇总
        $chunk_type = [24*60,1,5,15,30,60,4*60,5*24*60,7*24*60,30*24*60];

        //查询redis 如果存在 就取redis的值
        $redis_key = 'c'.$id.'_'.$time_type;
        $redis_val = Redis::get($redis_key);
        if ($redis_val){
            return json_decode($redis_val,true);
        }
        $close_prices = [];
        $res = [];
        $time = time();
        //取一个能整除的时间
        $time_len = $chunk_type[$time_type]; //时间间隔
        if ($time_type <= 5 && $time_type != 0 ){
            $minute = date('i'); //当前分钟数
            $ceil_minute = floor($minute/$time_len) * $time_len; //能被整除的分钟数
            $end_time = strtotime(date('Y-m-d H:0:0',$time)) + $ceil_minute*60;
            $end_date = date('Y-m-d H:i:00',$end_time+60);
            $start_date = date('Y-m-d H:i',$end_time - $date_type[$time_type]*60);
            $chunk_num = $time_len;

        }elseif($time_type == 6){
            $hour = date('H'); //当前小时数
            $ceil_hour = floor($hour / ($time_len/60)) * $time_len/60;
            $end_time = strtotime(date('Y-m-d',$time)) + $ceil_hour*60*60;
            $end_date = date('Y-m-d H:01:00',$end_time);
            $start_date = date('Y-m-d H:00:00',$end_time - $date_type[$time_type]*60);
            $chunk_num = $time_len;

        }else{
            //先查出每一天的开盘价、收盘价、最高价、最低价、总数量
            //再按照所选天数分片
            $end_date =  date('Y-m-d',strtotime('+1day'));
            $end_time = strtotime(date('Y-m-d'));
            $start_date = date('Y-m-d',$end_time - $date_type[$time_type]*60);

            $list = CurrencyLog::where(['cid'=>$id])
                ->select(DB::raw('time,max(high_price*1) max,min(lower_price*1) min,sum(amount*1) sum'))
                ->groupBy('time')
                ->get();
            //取出时间区间
            $times = $list->pluck('time');
            foreach ($times as $key=>$item){
                $first= CurrencyLog::where(['time'=>$item,'cid'=>$id])->first()->toArray();
                $last= CurrencyLog::where(['time'=>$item,'cid'=>$id])->orderBy('id','DESC')->first()->toArray();
                $open_price = $first['open_price'];
                $close_price = $last['close_price'];
                $close_prices[] = $close_price;
                $res[$key][] = date('Y-m-d',$list[$key]['time']);
                $res[$key][] = $open_price;
                $res[$key][] = $close_price;
                $res[$key][] = $list[$key]['min'];
                $res[$key][] = $list[$key]['max'];
                $res[$key][] = $list[$key]['sum'];
                $res[$key][] = 0;
            }
            $res1= [];
            $chunk_num = $time_len/24/60;
            $chunk_arr = array_chunk($res,$chunk_num);
            foreach ($chunk_arr as $key=>$item){
                if (count($item) < $chunk_num){ //当数据量不满足条件，则停止循环
                    break;
                }
                $time = $item[0][0];
                $open = $item[0][1];
                $close = $item[count($item)-1][2];
                $count_num = 0;
                $max_prices = [];
                $min_prices = [];
                foreach($item as $value){
                    $min_prices[] = $value[3];
                    $max_prices[] = $value[4];
                    $count_num += $value[5];
                }
                $max = max($max_prices);
                $min = min($min_prices);
                $res1[$key][0] = $time;
                $res1[$key][1] = price_format($open);
                $res1[$key][2] = price_format($close);
                $res1[$key][3] = price_format($min);
                $res1[$key][4] = price_format($max);
                $res1[$key][5] = $count_num;
                $res1[$key][6] = 0;

            }
            $res = $res1;
            Redis::setex($redis_key,58,json_encode(compact('res','close_prices')));
            return compact('res','close_prices');
        }

        $list = $this->where(['cid'=>$id])
            ->whereBetween('created_at',[$start_date,$end_date])
            ->orderby('id','DESC')
            ->get()->toArray();
        $chunk_arr = array_chunk($list,$chunk_num);
        $res1= [];
        $close_prices = [];
        foreach ($chunk_arr as $key=>$item){
            if (count($item) < $chunk_num){ //当数据量不满足条件，则停止循环
                break;
            }
            $time = $item[0]['time'] + $item[0]['minute_ident'] * 60;
            $time = date('Y-m-d H:i:00',$time);
            if ($chunk_num == 1){ //当选取1分钟时
                $close = $item[0]['close_price'];
                $open = $item[0]['open_price'];
            }else{
                $close = $item[0]['open_price'];
                $open = $item[count($item)-1]['close_price'];
            }

            $close_prices[] = $close;
            $count_num = 0;
            $max_prices = [];
            $min_prices = [];
            foreach($item as $value){
                $min_prices[] = $value['lower_price'];
                $max_prices[] = $value['high_price'];
                $count_num += $value['amount'];
            }
            $max = max($max_prices);
            $min = min($min_prices);
            $res1[$key][0] = $time;
            $res1[$key][1] = price_format($open);
            $res1[$key][2] = price_format($close);
            $res1[$key][3] = price_format($min);
            $res1[$key][4] = price_format($max);
            $res1[$key][5] = $count_num;
            $res1[$key][6] = 0;
        }
        $res = array_reverse($res1);
        $close_prices = array_reverse($close_prices);
        Redis::setex($redis_key,58,json_encode(compact('res','close_prices')));
        return compact('res','close_prices');
    }



    protected function getEMA(array $close_prices,int $num)
    {
        $alf = 2/($num+1);
        $ema_arr = [];
        foreach ($close_prices as $key=>$item){
            if ($key == 0){
                $EMA = $alf*$item;
            }else{
                $last_ema = $ema_arr[$key-1];
                $EMA = $alf*($item - $last_ema) + $last_ema;
            }
            $ema_arr[$key] = $EMA;
        }

        return $ema_arr;
    }

    protected function getDEA(array $DIF)
    {
        $dea_arr = [];
        foreach ($DIF as $key=>$item){
            if ($key == 0){
                $DEA = $item * 2/10;
            }else{
                $last_dea = $dea_arr[$key-1];
                $DEA = $last_dea*8/10 + $item*2/10;
            }
            $dea_arr[$key] =$DEA;
        }

        return $dea_arr;
    }

    /**
     * 获取K线图socket所需数据
     * @param $id 币种id
     * @param $time_type 时间
     * @return mixed
     */
    public function  get_kline_data($id,$time_type)
    {
        $currency_log = $this->get_kline($id,$time_type);
        $close_prices = $currency_log['close_prices'];
        $res = $currency_log['res'];

        $EMA12 = $this->getEMA($close_prices, 12);
        $EMA26 = $this->getEMA($close_prices, 26);
        $DIF = $this->get_DIF($EMA12, $EMA26);
        $DEA = $this->getDEA($DIF);
        $MACD = $this->get_MACD($DIF, $DEA);

        foreach ($res as $key => $item) {
            $res[$key][] = number_format($MACD[$key],2);
            $res[$key][] = number_format($DIF[$key],2);
            $res[$key][] = number_format($DEA[$key],2);
        }
        return $res;
    }

    /**
     * 获取开盘价
     * @date 2018/04/02
     * @auhtor yanggang
     * @param $id 币种id
     * @return int
     */
    public function getOpenPrice($id)
    {
        $time = strtotime(date('Y-m-d'));
        $list = $this->where(['cid'=>$id,'time'=>$time])->first();
        $open_price = $list? $list['open_price']:Currency::where(['id'=>$id])->value('official_price');
        return $open_price;
    }

    /**
     * 获取首页的币种数据
     * @author: yanggang
     * @date: 2018/4/17 0017
     * @return array
     */
    public function     get_index_socket_data()
    {
        $where['online_switch'] = 1;
        $where['pay_switch'] = 1;
        $where['buy_switch'] = 1;
        $orders = Currency::with('order')
            ->where($where)
            ->where('is_standard','!=',1)
            ->orderBy('orderby', 'asc')
            ->get();
        $btc = [];
        $map = [
            'type'=>1
        ];
        foreach ($orders as $order) {
            $arr = $order->select('id as cid', 'logo', 'name', 'name_en','official_price')->find($order->id)->toArray();

            //最高价
//            $max_price = $order->order()->where($map)->max('price') ?? $arr['official_price'];
            //最低价
//            $min_price = $order->order()->where($map)->min('price') ?? $arr['official_price'];
            //成交总价
//            $sum_price = $order->order()->where($map)->sum('total_price') ?? 0;
            //成交总量
            $order_count = $order->order()->where($map)->sum('num') * 1;
            //最新价
            $lasted_order = $order->order()->where($map)->orderBy('id', 'DESC')->first();
            $lasted_price = $lasted_order['price'] ?? $arr['official_price'];
            //收盘价
            $close_price = (new CurrencyLog())->get_last_close_price($order->id);
            //涨幅
            $gains_data = $this->get_gains($close_price,$lasted_price);
            $gains = $gains_data['gains'];
            $gains_type = $gains_data['gains_type'];
//            $arr['max_price'] = '$'.price_format($max_price);
//            $arr['min_price'] = '$'.price_format($min_price);
//            $arr['sum_price'] = '$'.price_format($sum_price);
//            if($order_count < 10000){
                $order_count = intval(round($order_count));
//            }else{
//                $order_count = price_format($order_count/10000).'万';
//            }

            $arr['order_count'] = $order_count;
            //按照汇率换算成人民币
            $exchange_rate = UsdRate()??6.3; //汇率
            $lasted_price_cny = $lasted_price * $exchange_rate;
            $arr['lasted_price_cny'] = price_format($lasted_price_cny);
            $arr['lasted_price'] = price_format($lasted_price);
            $arr['unit'] = $this->unit($arr['name_en']);
            $arr['gains'] = $gains;
            $arr['gains_type'] = $gains_type;
            $arr['logo'] = empty($arr['logo'])?'':config('alioss.host').'/'.$arr['logo'];

            array_push($btc, $arr);
        }

        return $btc;
    }

    /**
     * 获取首页二级行情页面的币种数据
     * @author: yanggang
     * @date: 2018/4/17 0017
     * @return array
     */
    public function get_index_market_data()
    {
        $orders = Currency::withCount('order')
            ->where(['online_switch'=>1])
            ->where('is_standard','!=',1)
            ->orderBy('orderby', 'DESC')
            ->get();
        $btc = [];
        $map = [
            'type'=>1
        ];
        foreach ($orders as $order) {
            $arr = $order->select('id', 'logo', 'name', 'name_en','official_price')->find($order->id)->toArray();
            //最新价
            $lasted_order = $order->order()->where($map)->orderBy('id', 'DESC')->first();
            $lasted_price = $lasted_order['price'] ??$arr['official_price'];
            //收盘价
            $close_price = (new CurrencyLog())->get_last_close_price($order->id);
            //涨幅
            $gains_data = $this->get_gains($close_price,$lasted_price);
            $arr['gains'] = $gains_data['gains'];
            $arr['gains_type'] = $gains_data['gains_type'];
            $arr['lasted_price'] = '$'.price_format($lasted_price);

            array_push($btc, $arr);
        }
        return $btc;
    }

    /**
     * 计算涨幅
     * @author: yanggang
     * @date: 2018/5/16 0016
     * @param $close_price 收盘价
     * @param $lasted_price 最新价
     * @return array
     */
    public function get_gains($close_price,$lasted_price)
    {
        //涨幅 TODO (最新价格-上一个交易日的收盘价)/上个交易日的收盘价*100%
        $gains_type = 0 ; //默认涨
        if (!$close_price || !$lasted_price) {
            $gains = '0.00%';
            $gains_type = 2;
        } else {
            $gains = price_format(($lasted_price - $close_price) / $close_price*100);
            if ($gains*1 < 0){
                $gains_type = 1; //跌
                $gains = $gains.'%';
            }elseif($gains*1 == 0){
                $gains = $gains.'%';
                $gains_type = 2;
            }else{
                $gains = '+'.$gains.'%';
            }
        }

        return ['gains'=>$gains,'gains_type'=>$gains_type];

    }
    public function get_kline_new($id,$time_type=0,$page=1)
    {

        //查询redis 如果存在 就取redis的值
        $redis_key = 'c'.$id.'_'.$time_type.'_'.$page;
        $redis_val = Redis::get($redis_key);
        if ($redis_val){
            return json_decode($redis_val,true);
        }
        $time_type_list = [1,3,20,1,8,1];//0 1分钟间距 1 3分钟间距 2 20分钟间距 3 1小时间距 4 8小时间距 5 1天
        $total_num_list = [16,63,500,25,168,1];//实际查询条数
        $time_len = $time_type_list[$time_type];
        $total_num = $total_num_list[$time_type];

        $map = [
            'cid'=>$id,
        ];

        $data = [];
        if($time_type < 3){
            //当月时间
            $query_month_end  = '-'.($page-1)*$total_num.'minute';
            $query_month_start  = '-'.$page*$total_num.'minute';

            $Model = new CurrencyLog();

        }elseif ($time_type < 5) {
            //当月时间
            $query_month_end  = '-'.($page-1)*$total_num.'hour';
            $query_month_start  = '-'.$page*$total_num.'hour';

            $Model = new CurrencyLogHour();

        } elseif ($time_type == 5) { //一个月
            //当月时间
            $query_month_end  = '-'.($page-1)*$total_num.'month';
            $query_month_start  = '-'.$page*$total_num.'month';

            $Model = new CurrencyLogDay();

        }

        $start_time = date('Y-m-d H:i',strtotime($query_month_start));
        $end_time = date('Y-m-d H:i',strtotime($query_month_end));

        $list = $Model
            ->where($map)
            ->orderBy('id','DESC')
            ->whereBetween('created_at',[$start_time,$end_time])
            ->get();

        if (collect($list)->isNotEmpty()){
            $list = collect($list)->toArray();
            $list = array_chunk($list, $time_len);
            //取出最大值
            foreach ($list as $key => $item) {
                $last = $item[0];
                $price = price_format($last['high_price']);
//                $time = strtotime(date('Y-m-d H:i:00', strtotime($last['created_at'])));
                if($time_type <3){
                    $time = date('H:i',strtotime($last['created_at']));
                }elseif ($time_type <5){
                    $time = date('H:00',strtotime($last['created_at']));

                }elseif ($time_type == 5){
                    $time = date('m-d',strtotime($last['created_at']));
                }
                $sort[$key] = $last['id'];
                $data[$key]['time'] = $time;
                $data[$key]['price'] = $price;
            }
        }

        //改为正序
        array_multisort($sort,$data);
        Redis::setex($redis_key,58,json_encode($data));
        return $data;

//        return compact('res','close_prices');
    }
}